#include "MyGame.h"
#include "Factory.h"

MyGame* MyGame::m_MyGame = NULL;

MyGame::MyGame()
{
    m_MyGame = this;
    this->password = "WaNd0r!P|r4t3sRuL3\n";

    Penjin::setApplicationName("Wandor");
    testLevel = false;
    nextState = NULL;
    levelList = NULL;
    gameState = NULL;
}

MyGame::~MyGame()
{
    delete levelList;
}

MyGame *MyGame::GetMyGame()
{
    return m_MyGame;
}

PENJIN_ERRORS MyGame::init()
{
    //Set up first level password and filename
    if (testLevel)
    {
        setInitialState(STATE_LEVEL);
    }
    else
    {
        setInitialState(STATE_TITLE);
    }
    gameTimer->start();
    GFX::setResolution(800,480);
    GFX::resetScreen();
    setFrameRate(30);
    return PENJIN_OK;
}

void MyGame::stateManagement()
{
    if (nextState) // called after pushing / poping a level
    {
        uint next = state->getNextState();
        if (next == STATE_LEVEL)
        {
#ifdef _DEBUG
            cout << "Using nextState" << endl;
#endif
            if (((WandorBaseState*)state)->pushed) //
            {
                // delete pushed state (it is safe to do here)
                delete state;
                state = NULL;
            }
            state = (BaseState*)nextState;
            ((WandorBaseState*)state)->Activate();
            nextState = NULL;
            return;
        }
        else // state swap has been aborted, delete pushed nextState
        {
            delete (WandorBaseState*)nextState;
            nextState = NULL;
        }
    }

    uint next;
    if(state) // normal state swap
    {
        next = state->getNextState();
        delete state;
        state = NULL;
    }
    else // first normal call of the game
    {
        next = STATE_TITLE;
    }

    switch(next) // normal state check
    {
    case STATE_TITLE: // Title: logos, intro
#ifdef _DEBUG
        cout << "Title State" << endl;
#endif
        state = new StateTitle;
        break;
    case STATE_MAIN: // Main menu
#ifdef _DEBUG
        cout << "Main State" << endl;
#endif
        state = new StateMain;
        break;
    case STATE_LEVEL: // Any playable level
        if (gameState == NULL) {
            gameState = new GameState();
            gameState->LoadGameState("game1.sav");
        }
#ifdef _DEBUG
        cout << "Level State " << levelData.FileName << endl;
#endif
        state = Factory::GetFactory()->GetLevel(levelData);
        //state = new Level(levelFileName, password);
        //((WandorBaseState*)state)->Activate();
        if ((not testLevel) && (((WandorBaseState*)state)->getType() == stLevel))
        {
            nextState = state;
            state = new StatePreLevel(((Level*)nextState)->getLevelName(),((Level*)nextState)->getAuthor(),((Level*)nextState)->getDescription(),"");
            #ifdef _DEBUG
            cout << "Showing pre-level screen" << endl;
            #endif
        } else {
            ((WandorBaseState*)state)->Activate();
        }
        break;
    default:
        cout << ErrorHandler().getErrorString(PENJIN_UNDEFINED_STATE);
        exit(PENJIN_UNDEFINED_STATE);
    }
}

PENJIN_ERRORS MyGame::argHandler(int argc, char **argv)
{
    for (int I = 0; I < argc; ++I)
    {
        cout << argv[I] << " ";
    }
    cout << endl;

    if(argc <= 1)
        return	PENJIN_NO_COMMANDLINE;
    else
    {
        //	Do further CMD processing
        for (int arg = 1; arg < argc; ++arg)
        {
            //	Check for commandline escape chars
            if(argv[arg][0] == '-' || argv[arg][0] == '/')
            {
                //	Look for arguments
                switch(argv[arg][1])
                {
                    //	Set Fullscreen
                case 'F':
                {
                    GFX::setFullscreen(true);
                    break;
                }
                // Set test level
                case 'L':
                case 'l':
                {
                    if (argc>arg+1)
                    {
#ifdef _DEBUG
                        cout << "Test level " << argv[arg+1] << endl;
#endif
                        // assume next arg is levelfilename
                        string filename = argv[arg+1];
                        SetLevelFileName(filename);
                        testLevel = true;
                        arg++;
                    }
                    break;
                }
#ifdef PLATFORM_GP2X
                case 'M':
                case 'm':
                {
                    loadMenu = true;
                    break;
                }
#endif
                default:
                {
                    return PENJIN_INVALID_COMMANDLINE;
                }
                }
            }
        }
    }
    return	PENJIN_OK;
}

///

void MyGame::SetPassword(CRstring password)
{
    this->password = password;
}

void MyGame::SetLevelFileName(CRstring filename)
{
    if (!testLevel) this->levelData =  levelList->ParseLevelLine(filename); //FileName = filename;
}

void MyGame::SetLevelData(LevelData level)
{
    if (!testLevel) this->levelData = level; //FileName = filename;
}

STATE_TYPE MyGame::GetStateType()
{
    return ((WandorBaseState *)state)->getType();
}

Level *MyGame::GetCurrentLevel()
{
    Level *l = (Level *)state;
    return l;
}

LevelMap *MyGame::GetCurrentLevelMap()
{
    LevelMap *l = (LevelMap *)state;
    return l;
}

LevelData MyGame::GetNextLevel(CRstring filename)
{
    if (testLevel) // test level - repeat over and over
    {
        LevelData current;
        current.LevelClass = "Level";
        current.FileName = filename;
        current.Params = "";
        return current;
    }
    else if (levelList) // a level list / chapter file, go to next level
    {
#ifdef _DEBUG
        cout << "Getting next level after " << filename << endl;
#endif
        return levelList->GetNextLevel(filename);
    }
    else // a single level - go back to menu
    {
        LevelData empty;
        empty.LevelClass = "Menu";
        empty.FileName = "";
        empty.Params = "";
        return empty;
    }
}

void MyGame::loadLevelList(CRstring filename)
{
    levelList = new LevelList(filename);
    // Set next level to first level in list
    //LevelData level =
    levelData = levelList->GetFirstLevel();
    //this->levelFileName = level.FileName;
}

// Push and pop functions

void MyGame::PushState(WandorBaseState *newState)
{
    if (state) // currently active state (usually level)
    {
        stateStack.push_back(((WandorBaseState*)state));

        state->setNextState(STATE_LEVEL); // initialize stateManagement function
        newState->pushed = true;
        nextState = newState;
#ifdef _DEBUG
        cout << "Pushing Level State" << endl;
#endif
    }
}

WandorBaseState *MyGame::PopState()
{
    if (stateStack.size() > 0)
    {
        if (state) // currently active state (the pushed state)
        {
            state->setNextState(STATE_LEVEL); // initialize stateManagement function
            // we can't delete the current level here as we might still be in an update loop
            nextState = stateStack.back();
            // I hope this does not call the destructor -- pop_back() does!
            // just in case, let's assign null first
            stateStack[stateStack.size()-1] = NULL;
            stateStack.resize(stateStack.size()-1);
#ifdef _DEBUG
            cout << "Popping Level State - Returning to normal queue" << endl;
#endif
        }
    }
    return ((WandorBaseState*)state);
}

void MyGame::PushNewLevel()
{
    Factory *f = Factory::GetFactory();
    if (state)
    {
        stateStack.push_back(((WandorBaseState*)state));
    }
#ifdef _DEBUG
    cout << "Pushing New Level State" << endl;
#endif
    state->setNextState(STATE_LEVEL); // initialize stateManagement function
    nextState = f->GetLevel(levelData);
    ((WandorBaseState*)nextState)->pushed = true;
    ((WandorBaseState*)nextState)->Activate();
}

void MyGame::LoadSaveGame(string filename)
{
    // should we save the current state first?
    // gameSate->SaveGameState(NULL);

    gameState = new GameState();
    gameState->LoadGameState(filename);
}
